package com.xwltz.common.phone.base;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xwltz.common.phone.algorithm.PhoneAlgorithm;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Optional;

/**
 * @description PhoneBase
 * @information on version 1.0 be created by @xwltz at 2021/11/08 15:48
 */
@SuppressWarnings("unused")
public class PhoneBase implements PhoneAlgorithm {
	protected static final Log logger = LogFactory.get();
	protected static int dataVersion;
	protected static ByteBuffer originalByteBuffer;
	protected static int indicesStartOffset;
	protected static int indicesEndOffset;

	@Override
	public void loadData(byte[] data) {
		originalByteBuffer = ByteBuffer.wrap(data).asReadOnlyBuffer().order(ByteOrder.LITTLE_ENDIAN);
		dataVersion = originalByteBuffer.getInt();
		indicesStartOffset = originalByteBuffer.getInt(4);
		indicesEndOffset = originalByteBuffer.limit();
	}

	@Override
	public Optional<PhoneModel> getInfo(String phoneNumber) {
		return Optional.empty();
	}

	//region 通用方法

	protected static PhoneModel parse(String phoneNumber, String oriString, IspEnum isp) {
		String[] split = oriString.split("\\|");
		if (split.length < 4) {
			throw new IllegalStateException("content format error");
		}
		return PhoneModel.builder()
				.phoneNum(phoneNumber)
				.province(split[0])
				.city(split[1])
				.zipCode(split[2])
				.areaZone(split[3])
				.cardType(isp.getDescribe())
				.build();
	}

	protected static boolean checkInvalidPhoneNumber(String phoneNumber) {
		logger.trace("try to resolve attribution of phone number: {}", phoneNumber);
		ByteBuffer byteBuffer = originalByteBuffer.asReadOnlyBuffer().order(ByteOrder.LITTLE_ENDIAN);

		if (phoneNumber == null) {
			logger.debug("phone number is null");
			return true;
		}
		int phoneNumberLength = phoneNumber.length();
		if (phoneNumberLength < 7 || phoneNumberLength > 11) {
			logger.debug("phone number {} is not acceptable, length invalid, length should be 11 or 7(for left 7 numbers), actual: {}", phoneNumber, phoneNumberLength);
			return true;
		}
		return false;
	}

	protected static int checkPhoneNumberIsNumber(String phoneNumber) {
		int attributionIdentity;
		try {
			attributionIdentity = Integer.parseInt(phoneNumber.substring(0, 7));
		} catch (NumberFormatException e) {
			logger.debug("phone number {} is invalid, is it numeric?", phoneNumber);
			return 0;
		}
		return attributionIdentity;
	}


	protected static Optional<PhoneModel> extract(String phoneNumber, int indexStart, ByteBuffer byteBuffer) {
		byteBuffer.position(indexStart);
		//noinspection unused
		int prefix = byteBuffer.getInt(); // it is necessary
		int infoStartIndex = byteBuffer.getInt();
		byte ispMark = byteBuffer.get();
		IspEnum isp = IspEnum.of(ispMark).orElse(IspEnum.UNKNOWN);

		byte[] bytes = new byte[determineInfoLength(infoStartIndex, byteBuffer)];
		byteBuffer.get(bytes);
		String oriString = new String(bytes);
		PhoneModel model = parse(phoneNumber, oriString, isp);
		return Optional.of(model);
	}

	protected static int determineInfoLength(int infoStartIndex, ByteBuffer byteBuffer) {
		byteBuffer.position(infoStartIndex);
		//noinspection StatementWithEmptyBody
		while ((byteBuffer.get()) != 0) {
			// just to find index of next '\0'
		}
		int infoEnd = byteBuffer.position() - 1;
		byteBuffer.position(infoStartIndex); //reset to info start index
		return infoEnd - infoStartIndex;
	}

	protected static int compare(int position, int key, ByteBuffer byteBuffer) {
		byteBuffer.position(position);
		int phonePrefix;
		try {
			phonePrefix = byteBuffer.getInt();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return Integer.compare(phonePrefix, key);
	}

	protected static int alignPosition(int pos) {
		int remain = ((pos - indicesStartOffset) % 9);
		if (pos - indicesStartOffset < 9) {
			return pos - remain;
		} else if (remain != 0) {
			return pos + 9 - remain;
		} else {
			return pos;
		}
	}

	//endregion
}
